package xyz.labmem.controller

import cn.hutool.core.lang.Console
import cn.hutool.core.thread.ExecutorBuilder
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONArray
import com.gluonhq.charm.glisten.control.ProgressBar
import com.jfoenix.controls.JFXButton
import com.sun.javafx.webkit.WebConsoleListener
import javafx.animation.FadeTransition
import javafx.application.Platform
import javafx.concurrent.Worker
import javafx.event.EventHandler
import javafx.fxml.FXML
import javafx.scene.image.Image
import javafx.scene.image.ImageView
import javafx.scene.layout.AnchorPane
import javafx.scene.layout.Background
import javafx.scene.layout.HBox
import javafx.scene.layout.Pane
import javafx.scene.paint.Paint
import javafx.scene.text.FontSmoothingType
import javafx.scene.web.WebEvent
import javafx.scene.web.WebView
import javafx.stage.FileChooser
import javafx.stage.StageStyle
import javafx.util.Duration
import netscape.javascript.JSObject
import org.controlsfx.control.StatusBar
import xyz.labmem.config.BrowserReptileTask
import xyz.labmem.core.annotation.FXController
import xyz.labmem.core.base.BaseController
import xyz.labmem.core.exception.LabRunException
import xyz.labmem.core.reflex.FXApplication
import xyz.labmem.core.util.getResourceFile
import xyz.labmem.core.util.gui.Loading
import xyz.labmem.core.util.gui.dragWin
import xyz.labmem.engine.LabEngine
import xyz.labmem.result.ResultUtil
import xyz.labmem.service.BrowserReptileSimpleServer
import xyz.labmem.service.ReptileOperating
import java.util.concurrent.ExecutorService
import kotlin.collections.HashMap
import kotlin.jvm.Throws


/**
 * @Author lty
 * @Date 2021/9/28 14:10
 */
@FXController(
    fxmlPath = "fxml/browserReptile.fxml",
    title = "浏览器爬虫",
    icon = "icon.png",
    only = true,
    main = true,
    tray = true,
    myTray = FxTray::class,
    loadContrName = "InitLoadingController"
)
class BrowserReptileController : BaseController() {

    final val post = 48602
    final val socketPost = 48603
    final val API_PREFIX = "/api/reptile"
    final val API_URL = "http://127.0.0.1:$post$API_PREFIX"
    final val STATIC_PATH = "/html/browserReptile"
    final val HTML_PATH = "http://127.0.0.1:$post$STATIC_PATH"
    final val fileChooser = FileChooser()
    final var executor: ExecutorService? = null
    val reptile = ReptileOperating(this)
    val engine = LabEngine(this)
    lateinit var server: BrowserReptileSimpleServer

    val view = ViewTool(this)

    private var jsConnector: JSObject? = null

    @FXML
    var topDrag: HBox? = null   //状态栏

    @FXML
    var winHide: JFXButton? = null

    @FXML
    var winClose: JFXButton? = null

    @FXML
    var webView: WebView? = null

    @FXML
    var viewPane: AnchorPane? = null

    @FXML
    var taskProgress: ProgressBar? = null

    @FXML
    var statusBar: StatusBar? = null

    @FXML
    var titleImg: ImageView? = null

    override fun controlInitDown() {
        var first = true
        //窗口类型
        stage.apply {
            initStyle(StageStyle.TRANSPARENT)
            scene.fill = null
            setOnShown {
                if (first)
                    loading.apply {
                        getMasker().text = "正在努力执行前端代码"
                        show()
                    }
                else
                    getTray().winMsg(null, "欢迎回来")
            }
        }

        root.apply {
            children.forEach {
                if (it is Pane) {
                    it.background = Background.EMPTY
                    it.style = "-fx-background-radius:12px;"
                }
            }
            topDrag?.background = Background.EMPTY
            topDrag?.style = "-fx-background-radius:12px;"
            statusBar?.background = Background.EMPTY
            statusBar?.style = "-fx-background-radius:0 0 12 12"
            style = "-fx-background-radius:12px;-fx-opacity: 0.95;-fx-background-color: rgb(216,178,173)"
            background = Background.EMPTY
        }

        //重新初始化loading
        loading = Loading(viewPane!!)

        //窗口拖动
        stage.dragWin( topDrag!!)
        view.updateStatus(-1.0, "前端正在努力加载..")
        //init webView
        val webEngine = webView!!.engine
        webView?.isContextMenuEnabled = false
        webView?.fontSmoothingType = FontSmoothingType.LCD;
        webEngine.isJavaScriptEnabled = true
        webEngine.load(HTML_PATH)
        webEngine.loadWorker.stateProperty().addListener { _, _, newValue ->
            if (Worker.State.SUCCEEDED == newValue) {
                //获取js对象
                jsConnector = webEngine.executeScript("getJsConnector()") as JSObject
                //放入初始化数值
                jsConnector!!.setMember("API_PREFIX", API_URL)
                jsConnector!!.setMember("HTML_PATH", HTML_PATH)
                //执行初始化程序
                jsConnector!!.call("init")
                taskProgress!!.progress = 0.8
            }
        }
        //JS回调
        webEngine.onAlert = EventHandler { event: WebEvent<String> ->
            val reqJson = JSON.parseObject(event.data)
            when (reqJson["type"]) {
                "alert" -> {
                    when (reqJson["level"]) {
                        "success" -> getTray().winMsgInfo("Success", reqJson["msg"].toString())
                        "failed" -> getTray().winMsgWarning(null, reqJson["msg"].toString())
                        "error" -> getTray().winMsgError(null, reqJson["msg"].toString())
                    }
                }
                "function" -> {
                    Thread {
                        when (reqJson["method"]) {
                            "test" -> Platform.runLater { reptile.test() }
                            "initError" -> initError("程序执行失败，请debug")
                            "getTaskList" -> server.getTaskList()
                            "editTask" -> server.editTask(reqJson["data"].toString())
                            "saveTask" -> server.saveTask(reqJson["data"].toString())
                            "getTask" -> server.getTask(reqJson["index"].toString().toInt())
                            "delTask" -> server.delTask(reqJson["index"].toString().toInt())
                            "selectFilePath" -> server.selectFilePath(reqJson["data"].toString())
                            "saveDeploy" -> server.saveDeploy(reqJson["data"].toString())
                            "runTask" -> server.runTask(reqJson["data"].toString())
                            "shutTask" -> {
                                try {
                                    executor?.let {
                                        it.shutdownNow()
                                        server.showLog("强制停止所有任务")
                                    }
                                    server.socketSend("shutTask_back", ResultUtil.success())
                                } catch (e: Exception) {
                                    e.printStackTrace()
                                    server.socketSend("shutTask_back", ResultUtil.failedMessage(e.message!!))
                                }
                            }
                        }
                    }.start()
                }
                "initSuccess" -> {
                    loading.hide()
                    jsConnector!!.call("websocket")
                    view.doneStatus()
                    getTray().winMsg(null, "初始化完成！")
                    first = false
                }
                "socketSuccess" -> Thread { webSuccessLoad() }.start()
            }
        }
        //JS console
        WebConsoleListener.setDefaultListener { _, message, lineNumber, sourceId ->
            Console.log(" [$sourceId:$lineNumber] : $message")
            if (first && (message.contains("Error") || message.contains("error") || message.contains("ERROR")))
                initError("前端执行报错，请debug")
        }
    }

    fun getTray(): FxTray {
        return tray as FxTray
    }

    override fun initialize() {
        titleImg?.let {
            it.image = Image(getResourceFile("icon.png").stream)
        }
        //状态栏按钮绑定
        winHide?.let { wh ->
            wh.onAction = EventHandler {
                FadeTransition(Duration.millis(300.0)).apply {
                    fromValue = 1.0 // 设置起始透明度为1.0，表示不透明
                    toValue = 0.2 // 设置结束透明度为0.0，表示透明
                    node = root // 设置动画应用的节点
                    onFinished = EventHandler {
                        stage.isIconified = true
                        stage.iconifiedProperty().addListener { e ->
                            if (!stage.isIconified)
                                FadeTransition(Duration.millis(300.0)).apply {
                                    fromValue = 0.2 // 设置起始透明度为1.0，表示不透明
                                    toValue = 1.0 // 设置结束透明度为0.0，表示透明
                                    node = root // 设置动画应用的节点
                                    play()
                                }
                        }
                    }
                    play() // 播放动画
                }
            }
            var btnStyle: String? = null
            wh.onMouseEntered = EventHandler {
                btnStyle = wh.style
                wh.style = "-fx-background-color: rgb(179,180,180)"
            }
            wh.onMouseExited = EventHandler {
                wh.style = btnStyle
            }
        }
        winClose?.let { wc ->
            wc.onAction = EventHandler {
                FadeTransition(Duration.millis(300.0)).apply {
                    fromValue = 1.0 // 设置起始透明度为1.0，表示不透明
                    toValue = 0.1 // 设置结束透明度为0.0，表示透明
                    node = root // 设置动画应用的节点
                    onFinished = EventHandler {
                        stage.close()
                    }
                    play() // 播放动画
                }
            }
//            wc.style="-fx-background-radius:0 20 0 0;"
            var btnFill: Paint? = null
            var btnStyle: String? = null
            wc.onMouseEntered = EventHandler {
                btnFill = wc.textFill
                btnStyle = wc.style
                wc.textFill = Paint.valueOf("WHITE")
                wc.style = "-fx-background-color: rgb(232,17,35);-fx-background-radius:0 12 0 0;"
            }
            wc.onMouseExited = EventHandler {
                wc.textFill = btnFill
                wc.style = btnStyle
            }
        }
    }

    fun initError(msg: String) {
        alertUtil.errorAlert(msg) {
            FXApplication.close()
        }.create()
    }

    /**
     * 当前端浏览器加载完成后操作
     */
    fun webSuccessLoad() {
        server.getTaskList()
    }

    @Throws(LabRunException::class)
    fun taskThreadRun(list: HashMap<Int, BrowserReptileTask>) {
        if (executor != null)
            throw LabRunException("线程池非空，请排查")
        val resultJSON = HashMap<Int, JSONArray>()
        executor = ExecutorBuilder.create()
            .setCorePoolSize(list.size)
            .setMaxPoolSize(list.size + 1)
            .build()
        list.forEach { (k, v) ->
            val res = JSONArray()
            resultJSON[k] = res
            server.showLog("开始执行任务【${v.name}】")
            executor!!.execute(engine.run(v).apply {
                progressProperty().addListener { v, _, _ ->
                    server.socketSend("taskProgress", HashMap<String, String>().apply {
                        put("index", k.toString())
                        put("progress", String.format("%.2f", v.value.toDouble() * 100))
                    })
                    Console.log("progressProperty:${v.value}")
                }
                messageProperty().addListener { msg, _, _ ->
                    if (msg.value.equals(ReptileOperating.Status.SUCCESS.name)) {
                        server.socketSend("taskDone", k)
                    }
                    if (msg.value.equals(ReptileOperating.Status.ERROR.name)) {
                        server.socketSend("taskError", k)
                    }
                }
            })
        }
        executor!!.shutdown()
        Thread {
            while (true) {
                if (executor!!.isTerminated) {
                    //任务都执行完毕
                    server.socketSendMethod("taskAllDone")
                    executor = null
                    server.showLog("所有任务执行结束，有问题的请看报错内容")
                    return@Thread
                }
                Thread.sleep(300)
            }
        }.start()
    }

}